#include "Logger.h"
#include "EPollPoller.h"
#include "Channel.h"

#include <cassert>
#include <unistd.h>
#include <cerrno>
#include <cstring>

// channel的状态标识
const int kNew = -1;    // 未在ChannelMap中，也没被Poller托管
const int kAdded = 1;   // 被Poller托管，在ChannelMap中
const int kDeleted = 2; // 已经被Poller删除，但仍在ChannelMap中

EPollPoller::EPollPoller(EventLoop *loop)
    : Poller(loop), epfd_(::epoll_create1(EPOLL_CLOEXEC)), events_(kInitEventListsSize)
{
    if (epfd_ < 0)
    {
        LOG_FATAL("epoll_create error: %d: %s", errno, strerror(errno));
    }
}

EPollPoller::~EPollPoller()
{
    close(epfd_);
}

Timestamp EPollPoller::poll(int timeoutMs, ChannelList *activeChannels)
{
    LOG_DEBUG("fd total count: %d, 属于loop: %p", channels_.size(),ownerLoop());
    int numEvents = epoll_wait(epfd_, &(*events_.begin()), static_cast<int>(events_.size()), timeoutMs);
    // errno是全局的，多线程，多个Poller，执行下面代码时errno可能会变，这里保存当前Poller的错误码
    int savedErrno = errno;
    Timestamp now(Timestamp::now());

    if (numEvents > 0)
    {
        LOG_DEBUG("%d events happened, 属于loop: %p",numEvents,ownerLoop());
        fillActiveChannels(numEvents, activeChannels);
        if (numEvents == events_.size())    //扩容
        {
            events_.resize(events_.size() * 2);
        }
    }
    else if (numEvents == 0)
    {
        LOG_DEBUG("nothing happened, 属于loop: %p",ownerLoop());
    }
    else
    {
        if (savedErrno != EINTR)
        {
            LOG_FATAL("EPollPoller::poll() error: %d: %s", savedErrno, strerror(errno));
        }
    }
    return now;
}

void EPollPoller::updateChannel(Channel *channel)
{
    const int index = channel->index();
    LOG_DEBUG("func=%s,fd=%d, events=%d, index=%d", __FUNCTION__, channel->fd(), channel->events(), index);
    if (index == kNew || index == kDeleted)
    {
        if (index == kNew) // ChannelMap中没有，Poller也没托管
        {
            int fd = channel->fd();
            channels_[fd] = channel;
        }

        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD, channel);
    }
    else // 表明已被Poller托管，但关心事件更新了
    {
        if (channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL, channel); // 这就是kDeleted的情况
            channel->set_index(kDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD, channel);
        }
    }
}

void EPollPoller::removeChannel(Channel *channel)
{
    LOG_DEBUG("func=%s,fd=%d", __FUNCTION__, channel->fd());
    channels_.erase(channel->fd());
    int index = channel->index();
    if (index == kAdded)
    {
        update(EPOLL_CTL_DEL, channel);
        LOG_DEBUG("fd=%d被移除",channel->fd());   
    }

    channel->set_index(kNew);
}

void EPollPoller::fillActiveChannels(int numEvents, ChannelList *activeChannels) const
{
    for(int i=0;i<numEvents;i++)
    {
        Channel* channel=static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel);
    }
}

// 更新epoll的监听事件
void EPollPoller::update(int op, Channel *channel)
{
    struct epoll_event ev;
    bzero(&ev, sizeof(ev));
    ev.data.ptr = channel;
    ev.events = channel->events();

    int n = epoll_ctl(epfd_, op, channel->fd(), &ev);
    if (n < 0)
    {
        if (op == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error: %d: %s", errno, strerror(errno));
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error: %d: %s", errno, strerror(errno));
        }
    }
}